#include <utillib/util/timerqueue.h>

using namespace utillib::util;

#ifdef _CUSTOM_TIMER

bool TimerObject::isExpireTimer()
{
	return ( m_isExpireTimer ); 
}

void TimerObject::setExpireTimer()
{
	m_isExpireTimer = true ; 
}

bool TimerQueueObject::operator < ( TimerQueueObject &rhs )
{
	return ( m_currentStartTime + m_notifyTime < rhs.m_currentStartTime + rhs.m_notifyTime );
}

bool TimerQueueObject::executeTimer()
{
	if ( m_object->isExpireTimer() == true ) return ( false );
	m_count++;
	if ( m_priority == TimerQueueObject::IDLE ) m_currentStartTime = GetTickCount();
	if ( m_priority == TimerQueueObject::REAL ) m_currentStartTime += m_notifyTime;
	if ( m_maxCount == EVENT_CONTINUE ) return ( true );
	if (m_count < m_maxCount) return ( true );
	return ( false );
}

TimerQueue::TimerQueue() 
{
}

TimerQueue::~TimerQueue()
{
	clear();
}

void TimerQueue::terminate()
{
	m_eventThreadStop.set();
	m_timerNotifyEvent.set();

	utillib::thread::Thread::terminate();
}

HANDLE TimerQueue::addTimer( DWORD notifyTime, TimerObject *object, bool executeAtStart, DWORD maxCount )
{
	TimerQueueObject *timerObject = TimerQueueObjectPool::getInstance()->pop();
	timerObject->m_timerID = ( HANDLE )timerObject;
	timerObject->m_notifyTime = notifyTime;
	timerObject->m_object = object;
	timerObject->m_currentStartTime = ( executeAtStart == true ) ? 0 : GetTickCount();
	timerObject->m_count = 0;
	timerObject->m_maxCount = maxCount;
	timerObject->m_isDeleteObject = true;

	push( timerObject );
	sort();

	m_timerNotifyEvent.set();

	return (timerObject->m_timerID);
}

bool TimerQueue::removeTimer( HANDLE timerID )
{
	{
		SYNC( &m_lockObject );
		listIter iter_end( m_queue.end() );
		for ( listIter iter = m_queue.begin(); iter != iter_end; )
		{
			TimerQueueObject *timerObject  = ( *iter );
			if (timerObject ->m_timerID == timerID)
			{
				iter = m_queue.erase( iter );
			}
			else ++iter;
		}
	}
	return ( true );
}

bool TimerQueue::removeTimer( TimerObject *object )
{
	{
		SYNC( &m_lockObject );
		listIter iter_end( m_queue.end() );
		for ( listIter iter = m_queue.begin(); iter != iter_end; )
		{
			TimerQueueObject *timerObject = ( *iter );
			if (timerObject->m_object == object)
			{
				iter = m_queue.erase( iter );
			}
			else ++iter;
		}
	}

	return ( true );
}

DWORD TimerQueue::run()
{
	for ( ;; )
	{
		if ( m_eventThreadStop.wait( 0 ) == true ) break;

		TimerQueueObject *timerObject = getHead();
		if ( timerObject )
		{
			bool result = false;
			if ( timerObject->m_currentStartTime != 0 )
			{
				DWORD checkTime = utillib::util::Util::getCheckTime( timerObject->m_currentStartTime );
				if ( checkTime < timerObject->m_notifyTime ) result = m_timerNotifyEvent.wait( timerObject->m_notifyTime - checkTime );
			}
			if ( result == false )
			{
				timerObject->m_object->notifyTimer();
				if ( !timerObject->executeTimer() )
				{
					if ( remove( timerObject ) == true )
						TimerQueueObjectPool::getInstance()->push( timerObject );
					continue;
				}
			}
			sort();
		}
		else 
		{
			m_timerNotifyEvent.wait( INFINITE );
		}
	};
	return ( 0 );
}


TimerQueueObject *TimerQueue::getHead()
{
	{
		SYNC( &m_lockObject );

		listIter iter = m_queue.begin();
		if ( iter == m_queue.end() ) return ( NULL );

		return ( *iter );
	}
}

TimerQueueSystem::TimerQueueSystem()
{
	m_timerQueue = new utillib::util::TimerQueue;
	utillib::thread::ThreadManager::getInstance()->add( m_timerQueue );
}

TimerQueueSystem::~TimerQueueSystem()
{
}

HANDLE TimerQueueSystem::addTimer( DWORD notifyTime, TimerObject *object, bool executeAtStart , DWORD maxCount )
{
	return ( m_timerQueue->addTimer( notifyTime, object, executeAtStart, maxCount ) );
}

bool TimerQueueSystem::removeTimer( HANDLE timerID )
{
	return ( m_timerQueue->removeTimer( timerID ) );
}

#else

bool TimerQueueObject::executeTimer()
{
	count++;
//	printf( "%d\r\n", GetTickCount() );

	if ( maxCount == EVENT_CONTINUE ) return ( true );
	if (count < maxCount) return ( true );

	return ( false );
};

void TimerQueueObject::notifyTimer()
{
	object->notifyTimer();
}

TimerQueue::TimerQueue()
{
	m_timerQueue = CreateTimerQueue();
}

TimerQueue::~TimerQueue()
{
	{
		SYNC( &m_lockObject );
		mapTimerObject::iterator iter_end( m_timerList.end() );
		for ( mapTimerObject::iterator iter = m_timerList.begin() ; iter != iter_end ; ++iter )
		{
			TimerQueueObject *timerObject  = ( *iter ).second;
			DeleteTimerQueueTimer( timerObject->m_handle, m_timerQueue, 0 );
			TimerQueueObjectPool::getInstance()->push( timerObject );
		}
		m_timerList.clear();
	}
	DeleteTimerQueue( m_timerQueue );
}

HANDLE TimerQueue::add( DWORD notifyTime, TimerObject *object, bool executeAtStart, DWORD maxCount )
{
	TimerQueueObject *timerObject = TimerQueueObjectPool::getInstance()->pop();
	timerObject->m_notifyTime = notifyTime;
	timerObject->m_object = object;
	timerObject->m_count = 0;
	timerObject->m_maxCount = maxCount;
	timerObject->m_timerQueue = this;
	timerObject->m_isDeleteObject = true;

	if ( executeAtStart == true )
		timerObject->notifyTimer();

	CreateTimerQueueTimer( &timerObject->m_handle, m_timerQueue, TimerQueue::run, timerObject , 0, timerObject->m_notifyTime, 0 );//WT_EXECUTELONGFUNCTION );
	{
		SYNC( &m_lockObject );
		m_timerList.insert( mapTimerObject::value_type( timerObject->m_handle, timerObject ) );
	}

	return (timerObject->handle );
}

bool TimerQueue::remove( HANDLE handle )
{
	{
		SYNC( &m_lockObject );
		mapTimerObject::iterator iter = m_timerList.find( handle );
		if ( iter == m_timerList.end() ) return ( false );
		TimerQueueObject *timerObject  = ( *iter ).second;
		timerObject->m_deleteFlag = true;
	}
	return ( true );
}

bool TimerQueue::deleteTimerQueue( HANDLE handle )
{
	TimerQueueObject *timerObject = NULL;
	{
		SYNC( &m_lockObject );
		mapTimerObject::iterator iter = m_timerList.find( handle );
		if ( iter == m_timerList.end() ) return ( false );
		timerObject  = ( *iter ).second;
		m_timerList.erase( iter );
	}
	if ( timerObject == NULL ) return ( false );

	DeleteTimerQueueTimer( m_timerQueue, timerObject->m_handle, 0 );
	TimerQueueObjectPool::getInstance()->push( timerObject );

	return ( true );
}

bool TimerQueue::isExist( HANDLE handle )
{
	{
		SYNC( &m_lockObject );
		mapTimerObject::iterator iter = m_timerList.find( handle );
		if ( iter == m_timerList.end() ) return ( false );
	}
	return ( true );
}

void CALLBACK TimerQueue::run( PVOID param, BOOLEAN timerOrWaitFired )
{
	TimerQueueObject *timerObject = ( TimerQueueObject* )param;

	if ( timerObject->m_timerQueue->isExist( timerObject->m_handle ) == false ) return;
	if ( timerObject->m_deleteFlag == true )
	{
		timerObject->m_timerQueue->deleteTimerQueue( timerObject->m_handle );
		return;
	}

	timerObject->notifyTimer();

	if ( timerObject->executeTimer() == false )
		timerObject->timerQueue->deleteTimerQueue( timerObject->m_handle );
}

TimerQueueSystem::TimerQueueSystem()
{
}

TimerQueueSystem::~TimerQueueSystem()
{
}

HANDLE TimerQueueSystem::add( DWORD notifyTime, TimerObject *object, bool executeAtStart , DWORD maxCount )
{
	return ( m_timerQueue.add( notifyTime, object, executeAtStart, maxCount ) );
}

bool TimerQueueSystem::remove( HANDLE handle )
{
	return ( m_timerQueue.remove( handle ) );
}
#endif